home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-12-11 | 7.0 KB | 360 lines | [TEXT/KAHL] |
- /***
- *
- * Scanner.cp - lexical scanner
- *
- * Original code: Copyright (c) 1991, by David Michael Betz. All rights reserved
- * Modifications and additions: Copyright © by Christopher E. Hyde, 1995
- *
- ***/
-
- #include "Bob.h"
- #include "Compiler.h"
-
- // Some useful definitions
- #define IfGetCh(tstCh, tok) { if ((ch = GetCh()) == (tstCh)) return (tok); \
- SaveCh(ch); }
- #define Hex(c) (isdigit(c) ? (c) - '0' : ((c) & 0x1F) + 9)
- #define IsIdChar(ch) (isalnum(ch) || ch == '_') // Is this a valid identifier character
-
- // Global variables
- SInt32 gTokVal; // numeric value
- char* gTokStr; // token string
- TToken pSaveTkn; // look ahead token
-
- // Local variables
- static CIStream* inStream; // input stream
- static int pSaveCh; // look ahead character
- static char* pLine; // last input line
- static char* pLPtr; // line pointer
- static int pLineNum; // line number
- static char pKeywords[] = "class\0static\0if\0else\0while\0return"
- "\0for\0break\0continue\0do\0new\0nil\0";
-
- // Prototypes
- static TToken ReadToken (void);
- static TToken GetString (void);
- static TToken GetCharacter (void);
- static int LiteralChar (void);
- static TToken GetId (int ch);
- static TToken GetNumber (int ch);
- static int SkipSpaces (void);
- static int GetCh (void);
-
-
- inline static void
- SaveCh (char ch)
- {
- pSaveCh = ch;
- }
-
-
- // Initialize the scanner
- void
- InitScanner (CIStream& iStream)
- {
- pLine = (char*) Calloc(kLineSize + kLitStrSize, 1);
- gTokStr = &pLine[kLineSize];
-
- // Remember the getc function and data
- inStream = &iStream;
-
- // Setup the line buffer
- pLPtr = pLine;
- *pLPtr = '\0';
- pLineNum = 0;
-
- // No lookahead yet
- SaveToken(kNoToken);
- SaveCh(0);
- }
-
-
- // Get the next token
- TToken
- Token (void)
- {
- TToken tkn = pSaveTkn;
-
- if (tkn != kNoToken)
- SaveToken(kNoToken);
- else
- tkn = ReadToken();
- return tkn;
- }
-
-
- // Get the name of a token
- KStr
- TokenName (TToken token)
- {
- static Str15 aTokenStr;
-
- if (token == kEOF)
- return "<eof>";
- else if (token >= _kTokenMin && token <= _kTokenMax) {
- GetIndString(aTokenStr, rTokenNames, token - _kTokenMin + 1);
- aTokenStr[aTokenStr[0] + 1] = 0;
- return KStr(&aTokenStr[1]);
- }
-
- aTokenStr[0] = token;
- aTokenStr[1] = '\0';
- return KStr(aTokenStr);
- }
-
-
- // Read the next token
- static TToken
- ReadToken (void)
- {
- int ch;
-
- // check the next character
- for (;;)
- switch (ch = SkipSpaces()) {
- case EOF: return kEOF;
- case '"': return GetString();
- case '\'': return GetCharacter();
- case '<': switch (ch = GetCh()) {
- case '=':
- return kLE;
- case '<':
- IfGetCh('=', kSHLEQ);
- return kSHL;
- default:
- SaveCh(ch);
- return '<';
- }
- case '=': IfGetCh('=', kEQ);
- return '=';
- case '!': IfGetCh('=', kNE);
- return '!';
- case '>': switch (ch = GetCh()) {
- case '=':
- return kGE;
- case '>':
- IfGetCh('=', kSHREQ);
- return kSHR;
- default:
- SaveCh(ch);
- return '>';
- }
- case '%': IfGetCh('=', kREMEQ);
- return '%';
- case '&': switch (ch = GetCh()) {
- case '&': return kAND;
- case '=': return kANDEQ;
- default: SaveCh(ch); return '&';
- }
- case '|': switch (ch = GetCh()) {
- case '|': return kOR;
- case '=': return kOREQ;
- default: SaveCh(ch); return '|';
- }
- case '^': IfGetCh('=', kXOREQ);
- return '^';
- case '+': switch (ch = GetCh()) {
- case '+': return kINC;
- case '=': return kADDEQ;
- default: SaveCh(ch); return '+';
- }
- case '-': switch (ch = GetCh()) {
- case '-': return kDEC;
- case '=': return kSUBEQ;
- case '>': return kMemRef;
- default: SaveCh(ch); return '-';
- }
- #if qExtensions
- case '.': return kMemRef;
- #endif
- case '*': IfGetCh('=', kMULEQ);
- return '*';
- case '/': switch (ch = GetCh()) {
- case '=':
- return kDIVEQ;
- case '/':
- while ((ch = GetCh()) != EOF)
- if (ch == '\r')
- break;
- break;
- case '*':
- for (int ch2 = ch = EOF; (ch2 = GetCh()) != EOF; ch = ch2)
- if (ch == '*' && ch2 == '/')
- break;
- break;
- default:
- SaveCh(ch);
- return '/';
- }
- break;
- case ':': IfGetCh(':', kCC);
- return ':';
- default: if (isdigit(ch))
- return GetNumber(ch);
- else if (isalpha(ch))
- case '_': return GetId(ch);
- else
- return ch;
- }
- }
-
-
- // Get a string
- static TToken
- GetString (void)
- {
- int ch;
-
- // get the string
- char* p = gTokStr;
- while ((ch = LiteralChar()) != EOF && ch != '"') {
- *p++ = ch;
- if (p > &gTokStr[kLitStrLen])
- ParseError("Literal string too long");
- }
- if (ch == EOF)
- SaveCh(EOF);
- gTokVal = p - gTokStr;
-
- return kString;
- }
-
-
- // Get a character constant
- static TToken
- GetCharacter (void)
- {
- gTokVal = LiteralChar();
-
- if (GetCh() != '\'')
- ParseError("Expecting a closing single quote");
- return kNumber;
- }
-
-
- // Get a character from a literal string
- static int
- LiteralChar (void)
- {
- int ch = GetCh();
-
- if (ch == '\\')
- switch (ch = GetCh()) {
- case '0': ch = 0; break;
- case 'n': ch = 13; break; // Swap around \n and \r
- case 'r': ch = 10; break;
- case 't': ch = '\t'; break;
- #if qExtensions
- case 'x':
- ch = GetCh();
- int ch2 = GetCh();
- if (!isxdigit(ch) || !isxdigit(ch2))
- ParseError("Expecting 2 hex digits");
- ch = (Hex(ch) << 4) + Hex(ch2);
- break;
- #endif
- case EOF: ch = '\\'; SaveCh(EOF); break;
- }
- return ch;
- }
-
-
- // Get an identifier
- static TToken
- GetId (int ch)
- {
- // get the identifier
- char* p = gTokStr; *p++ = ch;
- while ((ch = GetCh()) != EOF && IsIdChar(ch)) {
- *p++ = ch;
- if (p > &gTokStr[kIdLen])
- ParseError("Identifier name too long");
- }
- SaveCh(ch);
- *p = '\0';
-
- // check to see if it is a keyword
- int i = _kFirstKeyword;
- for (KStr k = pKeywords; *k; ++i) {
- if (strcmp(k, gTokStr) == 0)
- return i;
- while (*k++)
- ;
- }
-
- return kIdentifier;
- }
-
-
- // Get a number
- static TToken
- GetNumber (int ch)
- {
- SInt32 num = ch - '0';
-
- // get the number
- while ((ch = GetCh()) != EOF && isdigit(ch))
- num = (num * 10) + ch - '0';
-
- gTokVal = num;
- SaveCh(ch);
-
- return kNumber;
- }
-
-
- // Skip leading spaces
- static int
- SkipSpaces (void)
- {
- int ch;
-
- while ((ch = GetCh()) != EOF && isspace(ch))
- ;
- return ch;
- }
-
-
- // Get the next character
- static int
- GetCh (void)
- {
- int ch = pSaveCh;
-
- // check for a lookahead character
- if (ch)
- SaveCh(0);
- else { // check for a buffered character
- while ((ch = (uchar) *pLPtr++) == '\0') {
- // check for being at the end of file
- if (inStream->IsEOF())
- return EOF;
-
- // read the next line
- inStream->Get(pLPtr = pLine, kLineSize);
- ++pLineNum;
- }
- }
-
- // return the current character
- return ch;
- }
-
-
- // Report an error in the current line
- void
- ParseError (KStr msg)
- {
- // Rredisplay the line with the error
- PrintErrF(">>> %s <<<\r>>> in line %d <<<\r%s", msg, pLineNum, pLine);
-
- for (char* src = pLine; src < pLPtr - 1; ++src)
- if (*src != '\t')
- *src = ' ';
- *src = '\0';
- PrintErrF("%s^\r", pLine);
-
- // Invoke the error trap
- Fail(errPrintedMessage);
- }
-